package com.acme.domain.client;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import com.acme.domain.account.Account;

public class Client implements Serializable {

    private static int counter = 0;

    private static synchronized int newID() {
	return counter++;
    }

    private int clientID = Client.newID();
    private static final long serialVersionUID = -6453327501271371480L;
    private String name;

    private Gender gender;

    private Set<Account> accounts = new HashSet<>();

    public Client(final String name, final Gender gender) {
	this.name = name;
	this.gender = gender;
    }

    public void addAccount(final Account account) {
	if (account == null) {
	    throw new NullPointerException();
	}
	accounts.add(account);
    }

    @Override
    public boolean equals(final Object obj) {
	if (this == obj) {
	    return true;
	}
	if (obj == null) {
	    return false;
	}
	if (getClass() != obj.getClass()) {
	    return false;
	}
	final Client other = (Client) obj;
	if (accounts == null) {
	    if (other.accounts != null) {
		return false;
	    }
	} else if (!accounts.equals(other.accounts)) {
	    return false;
	}
	if (gender == null) {
	    if (other.gender != null) {
		return false;
	    }
	} else if (!gender.equals(other.gender)) {
	    return false;
	}
	if (name == null) {
	    if (other.name != null) {
		return false;
	    }
	} else if (!name.equals(other.name)) {
	    return false;
	}
	if (clientID != other.clientID) {
	    return false;
	}
	return true;
    }

    public Account getAccount(final int id) {
	for (Account account : accounts) {
	    if (account.getAccountNumber() == id) {
		return account;
	    }
	}
	return null;
    }

    public List<Account> getAccountsList() {
	List<Account> list = new LinkedList<>(accounts);
	return Collections.unmodifiableList(list);
    }

    public String getName() {
	return name;
    }

    public String getSalutation() {
	if (gender != null) {
	    return gender.getSalutation() + " " + name;
	}
	return name;
    }

    @Override
    public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result
		+ ((accounts == null) ? 0 : accounts.hashCode());
	result = prime * result + ((gender == null) ? 0 : gender.hashCode());
	result = prime * result + ((name == null) ? 0 : name.hashCode());
	result += clientID;
	return result;
    }

    @Override
    public String toString() {
	StringBuffer accs = new StringBuffer(getSalutation() + " accounts:\n");
	for (Account account : accounts) {
	    accs.append(account);
	    accs.append("\n");
	}
	return accs.toString();
    }
}
